package com.eelpo.framework.socket.session;

import java.util.Collection;
import java.util.Collections;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import org.jboss.netty.channel.Channel;

import com.eelpo.framework.socket.SocketResponse;
import com.eelpo.framework.socket.listener.SocketSessionListener;

/**
 * Socket 会话缓存
 * 
 * @author <a href="mailto:whz-work@163.com">汪洪州</a>
 * 
 * @since 1.0 Create on May 30, 2012
 */
public class SocketSessionCache {

	private static final String ALL_SESSION = "ALL";
	private static SocketSessionListener sessionListener;
	private static final ConcurrentHashMap<Long, SocketSession> SESSION_CACHE = new ConcurrentHashMap<Long, SocketSession>();
	private static final ConcurrentHashMap<String, SocketSessionGroup> SESSIONGROUP_CACHE = new ConcurrentHashMap<String, SocketSessionGroup>();

	public static void setSessionListener(SocketSessionListener sessionListener) {
		SocketSessionCache.sessionListener = sessionListener;
	}

	public static SocketSessionGroup getSessionGroup(String name) {
		if (!SESSIONGROUP_CACHE.containsKey(name)) {
			synchronized (SESSIONGROUP_CACHE) {
				if (!SESSIONGROUP_CACHE.containsKey(name)) {
					SocketSessionGroup socketSessionGroup = new SocketSessionGroup(name);
					SESSIONGROUP_CACHE.put(name, socketSessionGroup);
					if (sessionListener != null) {
						sessionListener.addSessionGroup(socketSessionGroup);
					}
				}
			}
		}
		return SESSIONGROUP_CACHE.get(name);
	}

	public static void joinSessionGroup(String name, SocketSession socketSession) {
		SocketSessionGroup socketSessionGroup = getSessionGroup(name);
		socketSessionGroup.add(socketSession);
		if (sessionListener != null) {
			sessionListener.joinSessionGroup(socketSession, socketSessionGroup);
		}
	}

	public static void leaveSessionGroup(String name, SocketSession socketSession) {
		SocketSessionGroup socketSessionGroup = getSessionGroup(name);
		if (socketSessionGroup != null) {
			socketSessionGroup.remove(socketSession);
			if (sessionListener != null) {
				sessionListener.leaveSessionGroup(socketSession, socketSessionGroup);
			}
		}
	}

	public static void addSession(Long id, SocketSession socketSession) {
		removeSession(id);
		SESSION_CACHE.put(id, socketSession);
		joinSessionGroup(ALL_SESSION, socketSession);
		if (sessionListener != null) {
			sessionListener.addSession(socketSession);
		}
	}

	public static void removeSession(Long id) {
		SocketSession socketSession = SESSION_CACHE.remove(id);
		if (socketSession != null) {
			leaveSessionGroup(ALL_SESSION, socketSession);
			socketSession.close();
			if (sessionListener != null) {
				sessionListener.removeSession(socketSession);
			}
		}
	}

	public static SocketSession getSocketSession(Channel channel) {
		for (SocketSession session : SESSION_CACHE.values()) {
			if (session.equals(channel)) {
				return session;
			}
		}
		return null;
	}

	public static boolean isOnline(Long id) {
		return SESSION_CACHE.containsKey(id);
	}

	public static int onlineCounts() {
		return SESSION_CACHE.keySet().size();
	}

	public static Set<Long> getSessions() {
		return Collections.unmodifiableSet(SESSION_CACHE.keySet());
	}

	public static Set<String> getSessionGroups() {
		return Collections.unmodifiableSet(SESSIONGROUP_CACHE.keySet());
	}

	public static void write(String name, SocketResponse message) {
		getSessionGroup(name).writeWithoutFuture(message);
	}

	public static void write(SocketResponse message, Long id) {
		SocketSession socketSession = SESSION_CACHE.get(id);
		if (socketSession != null) {
			if (socketSession.isConnected()) {
				socketSession.writeWithoutFuture(message);
			} else {
				removeSession(id);
			}
		}
	}

	public static void write(SocketResponse message, Long... ids) {
		for (Long id : ids) {
			write(message, id);
		}
	}

	public static void write(SocketResponse message, Collection<Long> ids) {
		for (Long id : ids) {
			write(message, id);
		}
	}
}
